package com.example.test_event_and_callback.infras.async;

import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public abstract class AsyncDemanderProcessor<MethodsType> {

    protected Map<String, MethodsType> mappedMethods = new HashMap<>();

    protected AsyncProviderProcessor<?> providerProcessor;

    public void setProviderProcessor(AsyncProviderProcessor<?> providerProcessor) {
        this.providerProcessor = providerProcessor;
    }

    public AsyncProviderProcessor<?> getProviderProcessor() {
        return providerProcessor;
    }

    public static AsyncDemanderProcessor<?> getInstance(Class<?> demanderClass, MethodCallType methodCallType){
        switch (methodCallType){
            case DIRECT_CALL -> {
                return new DemanderProcessorDirectCall(demanderClass);
            }
            case METHOD_HANDLE -> {
                return new DemanderProcessorMethodHandle(demanderClass);
            }
            case JAVA_REFLECTION -> {
                return new DemanderProcessorReflection(demanderClass);
            }
        }
        throw new RuntimeException("调用策略不存在");
    }

    protected void init(Class<?> demanderClass){
        Map<String, Method> methodMappedByName = Stream.of(demanderClass.getDeclaredMethods())
                .collect(Collectors.toMap(Method::getName, method -> method));
        Field[] fields = demanderClass.getDeclaredFields();
        for (Field field : fields) {
            String fieldName = field.getName();
            // 尝试查找 setter 方法，先按照 Java Bean 规范的 setXxx 尝试
            Method setterMethod = methodMappedByName.get("set" +  StringUtils.capitalize(fieldName));
            // 如果按照 setXxx 没有找到，尝试直接以 field 名称作为方法名查找
            if (setterMethod == null) {
                setterMethod = methodMappedByName.get(fieldName);
            }
            if (setterMethod != null && setterMethod.getParameterCount() == 1){
                mappedMethods.put(field.getName(), exchangeMethod(field,setterMethod));
                continue;
            }
            throw new RuntimeException(demanderClass + "类中" + fieldName + "属性不存在标准的Set方法");
        }
    }

//    public void setMappedProviderMethod(Map<String, ?> mappedProviderMethod) {
//        this.mappedProviderMethod = mappedProviderMethod;
//    }

    abstract MethodsType exchangeMethod(Field field, Method method);

    abstract <T extends Demander> void setParam(T dto, String paramName, Object param) throws Throwable;

}
